package base.transporte;

import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

import base.LinkedBlockingQueue;

public class Emissor implements Runnable {

	private BlockingQueue<SRPacket> fila_pacotes;
	// private BlockingQueue<Thread> fila_threads;
	private BlockingQueue<EnviaPacote> fila_enviadores;
	private final ExecutorService pool;
	private int nextSeqNum;
	private SRSocket conector;
	@SuppressWarnings("unused")
	private String nome;
	Velocimetro velocimetro;
	EstimadorRTT estimadorRTT;

	public Emissor(SRSocket conector, String nome) {
		this.nome = nome;
		this.conector = conector;
		// fila_threads = new LinkedBlockingQueue<Thread>(windowSize);
		fila_enviadores = new LinkedBlockingQueue<EnviaPacote>(Constantes.windowSize);
		fila_pacotes = new LinkedBlockingQueue<SRPacket>(3 * Constantes.windowSize);
	//	pool = Executors.newFixedThreadPool(Constantes.windowSize);
		pool = Executors.newFixedThreadPool(4);
		velocimetro = new Velocimetro();
		estimadorRTT = new EstimadorRTT();
	}

	public void inserirPacote(SRPacket pacote) {
		try {
			this.fila_pacotes.put(pacote);
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	public Velocimetro getVelocimetro() {
		return this.velocimetro;
	}

	public boolean isEmpty() {
		return fila_pacotes.isEmpty();
	}

	public void desligar() {
		pool.shutdown();
		try {
			pool.awaitTermination(1000, TimeUnit.MILLISECONDS);
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		pool.shutdownNow();
	}

	@Override
	public void run() {
		SRPacket pacote = null;
		// Thread thread_enviador;
		EnviaPacote enviador;
		boolean serving = true;

		while (serving) {
			if (fila_enviadores.size() < Constantes.windowSize) {
				try {
					pacote = fila_pacotes.take();
				} catch (InterruptedException e) {
					serving = false;
				}
				if (serving) {
					if (pacote != null) {
						pacote.setSeqNum(nextSeqNum);
						nextSeqNum++;
						enviador = new EnviaPacote(pacote, conector, estimadorRTT);

//						 Thread thread_enviador;
//						 thread_enviador = new Thread(enviador);
//						 thread_enviador.setPriority(Thread.MIN_PRIORITY);
//						 thread_enviador.start();

						pool.execute(enviador);
						try {
							fila_enviadores.put(enviador);
							// fila_threads.put(thread_enviador);
						} catch (InterruptedException e) {
							// TODO Auto-generated catch block
							e.printStackTrace();
						}
					}
				}
			}

			if (serving) {
				while (!fila_enviadores.isEmpty() && fila_enviadores.peek().isDone()) {
					try {
						//fila_threads.take();
						enviador = fila_enviadores.take();
						velocimetro.informarTransferencia(enviador.getPacote().getData().length);
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
				}
			}
			
		}
	}
}
